home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / DECFRAME.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  26KB  |  846 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1992, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.23  $
  6. //
  7. // Implementation of class TDecoratedFrame
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_DECFRAME_H)
  12. # include <owl/decframe.h>
  13. #endif
  14. #if !defined(OWL_MESSAGEB_H)
  15. # include <owl/messageb.h>
  16. #endif
  17. #if !defined(OWL_TOOLTIP_H)
  18. # include <owl/tooltip.h>
  19. #endif
  20.  
  21. OWL_DIAGINFO;
  22. DIAG_DECLARE_GROUP(OwlWin);   // diagnostic group for windows
  23. DIAG_DECLARE_GROUP(OwlCmd);   // diagnostic group for commands
  24.  
  25. #if !defined(SECTION) || SECTION == 1
  26.  
  27. DEFINE_RESPONSE_TABLE2(TDecoratedFrame, TFrameWindow, TLayoutWindow)
  28.   EV_WM_ENTERIDLE,
  29.   EV_WM_MENUSELECT,
  30.   EV_WM_SIZE,
  31. END_RESPONSE_TABLE;
  32.  
  33. const uint  BLANK_HELP = UINT_MAX;
  34.  
  35. //
  36. //
  37. //
  38. TDecoratedFrame::TDecoratedFrame(TWindow*        parent,
  39.                                  const char far* title,
  40.                                  TWindow*        clientWnd,
  41.                                  bool            trackMenuSelection,
  42.                                  TModule*        module)
  43. :
  44.   TLayoutWindow(parent, title, module)
  45. {
  46.   // Initialize virtual bases, in case the derived-most used default ctor
  47.   //
  48.   TWindow::Init(parent, title, module);
  49.   TFrameWindow::Init(clientWnd, false);
  50.  
  51.   TLayoutMetrics  metrics;
  52.  
  53.   TrackMenuSelection = trackMenuSelection;
  54.   MenuItemId = 0;
  55.   SettingClient = false;
  56.  
  57.   if (!ClientWnd)
  58.     ClientWnd = new TWindow(this, "\007");  // create dummy placeholder
  59.  
  60.   if (ClientWnd->Attr.Style & WS_BORDER) {
  61.     metrics.X.SameAs(lmParent, lmLeft);
  62.     metrics.Y.SameAs(lmParent, lmTop);
  63.     metrics.Width.SameAs(lmParent, lmRight);
  64.     metrics.Height.SameAs(lmParent, lmBottom);
  65.   }
  66.   else {
  67.     metrics.X.Set(lmLeft, lmRightOf, lmParent, lmLeft);
  68.     metrics.Y.Set(lmTop, lmBelow, lmParent, lmTop);
  69.     metrics.Width.Set(lmRight, lmLeftOf, lmParent, lmRight);
  70.     metrics.Height.Set(lmBottom, lmAbove, lmParent, lmBottom);
  71.   }
  72.  
  73.   SetChildLayoutMetrics(*ClientWnd, metrics);
  74. }
  75.  
  76. //
  77. // Override SetupWindow in order to layout & position decorations
  78. //
  79. void
  80. TDecoratedFrame::SetupWindow()
  81. {
  82.   TFrameWindow::SetupWindow();
  83.  
  84.   // Size/position child windows. Don't wait until we get the WM_SIZE event
  85.   // because by then the windows will have been displayed on the screen
  86.   //
  87.   TRect  clientRect = GetClientRect();
  88.  
  89.   ClientSize.cx = clientRect.right;
  90.   ClientSize.cy = clientRect.bottom;
  91.  
  92.   Layout();
  93. }
  94.  
  95. //
  96. // Handle SetClientWindow() here to manage fixing up the layout metrics of
  97. // all the children before & after the client is changed.
  98. //
  99. TWindow*
  100. TDecoratedFrame::SetClientWindow(TWindow* clientWnd)
  101. {
  102.   TLayoutMetrics metrics;
  103.   GetChildLayoutMetrics(*ClientWnd, metrics);
  104.   if (!clientWnd)
  105.     clientWnd = new TWindow(this, "\007");  // create dummy placeholder
  106.  
  107.   clientWnd->SetParent(this);
  108.   SetChildLayoutMetrics(*clientWnd, metrics);
  109.  
  110.   TWindow* oldWnd = GetClientWindow();
  111.  
  112.   // Make sure that all child metrics that were based on the old client window
  113.   // get updated to the new client
  114.   //
  115.   TWindow* first = GetFirstChild();
  116.   if (first) {
  117.     TWindow* child = first;
  118.     do {
  119.       if (GetChildLayoutMetrics(*child, metrics)) {
  120.         if (metrics.X.RelWin == oldWnd)
  121.           metrics.X.RelWin = clientWnd;
  122.         if (metrics.Y.RelWin == oldWnd)
  123.           metrics.Y.RelWin = clientWnd;
  124.         if (metrics.Width.RelWin == oldWnd)
  125.           metrics.Width.RelWin = clientWnd;
  126.         if (metrics.Height.RelWin == oldWnd)
  127.           metrics.Height.RelWin = clientWnd;
  128.         SetChildLayoutMetrics(*child, metrics);
  129.       }
  130.       child = child->Next();
  131.     } while (child != first);
  132.   }
  133.  
  134.   // Now let the TFrameWindow set the client. Then delete the old client if it
  135.   // was our temporary place holder. Set a flag while the client is being set
  136.   // so that RemoveChild() below knows that we are taking care of things.
  137.   //
  138.   SettingClient = true;
  139.   oldWnd = TFrameWindow::SetClientWindow(clientWnd);
  140.   SettingClient = false;
  141.   if (HiUint16(uint32(oldWnd->Title)) && oldWnd->Title[0] == 007) {
  142.     oldWnd->Destroy();
  143.     delete oldWnd;
  144.     oldWnd = 0;
  145.   }
  146.  
  147.   // Relayout the children to get the new client sized right
  148.   //
  149.   Layout();
  150.  
  151.   return oldWnd;
  152. }
  153.  
  154. //
  155. // Make sure that both bases get a chance to see the child removed. TWindow's
  156. // will be called twice, but the second call will be ignored. If we are
  157. // removing the client, and we are not in the process of setting the client,
  158. // then call SetClientWindow to put in a placeholder.
  159. //
  160. void
  161. TDecoratedFrame::RemoveChild(TWindow* child)
  162. {
  163.   if (child == ClientWnd && !SettingClient)
  164.     SetClientWindow(0);
  165.   TFrameWindow::RemoveChild(child);
  166.   TLayoutWindow::RemoveChild(child);
  167. }
  168.  
  169. //
  170. // Give the decorations an opportunity to do pre-processing. Don't bother
  171. // checking the client window since it is typically in the focus chain and
  172. // will be given an opportunity to do pre-processing
  173. //
  174. bool
  175. TDecoratedFrame::PreProcessMsg(MSG& msg)
  176. {
  177.   TWindow*  firstChild = GetFirstChild();
  178.  
  179.   if (firstChild) {
  180.     TWindow*  child = firstChild;
  181.  
  182.     do {
  183.       if (child != ClientWnd && child->GetHandle() &&
  184.          (child->GetWindowLong(GWL_STYLE) & WS_VISIBLE) &&
  185.           child->PreProcessMsg(msg))
  186.         return true;
  187.  
  188.       child = child->Next();
  189.     } while (child != firstChild);
  190.   }
  191.  
  192.   return TFrameWindow::PreProcessMsg(msg);
  193. }
  194.  
  195. //
  196. // Retrieves the hint text associated with a particular Id
  197. //
  198. int
  199. TDecoratedFrame::GetHintText(uint id, char* buf, int size,
  200.                           THintText hintType) const
  201. {
  202.  
  203.   int numBytes = 0;
  204.   if (hintType == htTooltip) {
  205.     // For tooltips, we first look if the same id exists on the
  206.     // window's menu and use the associated menu string.
  207.     //
  208.     if (::IsMenu(GetMenu()) &&
  209.         TUser::GetMenuString(GetMenu(), id, buf, size, MF_BYCOMMAND)) {
  210.       // Trim accelerator text e.g., '\tCtrl+X' (if any)
  211.       //
  212.       char* c = strchr(buf, '\t');
  213.       if (c)
  214.         *c = 0;
  215.  
  216.       // Accelerator can be \b instead of \t (NOTE: \a in .rc make a \b
  217.       // in res)
  218.       //
  219.       c = strchr(buf, '\b');
  220.       if (c)
  221.         *c = 0;
  222.  
  223.       // Trim trailing dots, e.g., '...' (if any)
  224.       //
  225.       int i;
  226.       for (i = strlen(buf) - 1; i >= 0; i--)
  227.         if (buf[i] == '.')
  228.           buf[i] = 0;
  229.         else
  230.           break;
  231.  
  232.       // Eliminate '&' (just emliminate first one)
  233.       //
  234.       i = -1;
  235.       while(buf[++i])
  236.         if (buf[i] == '&') {
  237.           do {
  238.             buf[i] = buf[i+1];
  239.             i++;
  240.           } while (buf[i]);
  241.           break;
  242.         }
  243.       numBytes = strlen(buf);
  244.     }
  245.     else {
  246.       // If the tip text cannot be retrieved from the menu, we then look
  247.       // for a string resource - The resource is expected to contain a
  248.       // longer status text followed by a '\n' and the tip text.
  249.       //
  250.       char resStr[256];
  251.       int len = GetModule()->LoadString(id, resStr, sizeof(resStr));
  252.       if (len == 0 && MergeModule != 0)
  253.           len = MergeModule->LoadString(id, resStr, sizeof(resStr));
  254.  
  255.       WARNX(OwlWin, len == 0, 0,
  256.           "TDecoratedFrame::GetHintText LoadString("
  257.           << *GetModule() << "," << id << ") Failed");
  258.  
  259.       char* pLF;
  260.       if (len && (pLF = strchr(resStr, '\n')) != 0) {
  261.         strncpy(buf, pLF+1, size);
  262.         numBytes = strlen(buf);
  263.       }
  264.     }
  265.   }
  266.  
  267.   if (hintType == htStatus) {
  268.     numBytes = GetModule()->LoadString(id, buf, size);
  269.     if (numBytes == 0 && MergeModule != 0)
  270.         numBytes = MergeModule->LoadString(id, buf, size);
  271.  
  272.     WARNX(OwlWin, numBytes == 0, 0,
  273.          "TDecoratedFrame::GetHintText LoadString("
  274.          << *GetModule() << "," << id << ") Failed");
  275.  
  276.     if (numBytes) {
  277.  
  278.       // Clear beyond the '\n' in case this string resource contains both
  279.       // a status and a tooltip hint text.
  280.       //
  281.       char* pLF = strchr(buf, '\n');
  282.       if (pLF) {
  283.         *pLF = 0;
  284.         numBytes = (int)(pLF - buf) -1;
  285.       }
  286.     }
  287.   }
  288.   return numBytes;
  289. }
  290.  
  291.  
  292. //
  293. // Handle WM_MENUSELECT to provide hint text in the status bar based on the
  294. // menu item id. Treat popup items seperatly and ask them for their ids.
  295. //
  296. void
  297. TDecoratedFrame::EvMenuSelect(uint menuItemId, uint flags, HMENU hMenu)
  298. {
  299.   if (TrackMenuSelection) {
  300.     if (flags == 0xFFFF && hMenu == 0) {  // Menu closing
  301.       TMessageBar*  messageBar = TYPESAFE_DOWNCAST(ChildWithId(IDW_STATUSBAR),
  302.                                                    TMessageBar);
  303.       if (messageBar)
  304.         messageBar->SetHintText(0);       // Restore text of status bar
  305.       MenuItemId = 0;                     //  ""  ""  ""  ""  ""  ""
  306.     }
  307.     else if (flags & MF_POPUP) {
  308.  
  309. #if 0 
  310. #else
  311.       // Retrieve id of popup menu
  312.       //
  313.       MenuItemId = TMenu(hMenu).GetMenuItemID(menuItemId);
  314. #endif
  315.     }
  316.     else if (flags & (MF_SEPARATOR | MF_MENUBREAK | MF_MENUBARBREAK)
  317.       || (menuItemId >= IDW_FIRSTMDICHILD && menuItemId < IDW_FIRSTMDICHILD+9)) {
  318.       MenuItemId = BLANK_HELP;  // display an empty help message
  319.                                 // could also restore bar at this point too
  320.     }
  321.     else {
  322.       MenuItemId = menuItemId;  // display a help message with this string Id
  323.     }
  324.   }
  325. }
  326.  
  327. //
  328. // Forward our size event to the layout window base, and not the frame base
  329. //
  330. void
  331. TDecoratedFrame::EvSize(uint sizeType, TSize& size)
  332. {
  333.   TLayoutWindow::EvSize(sizeType, size);
  334.  
  335.   // Since TFrameWindow::EvSize wasn't called, broadcast
  336.   // relevant info to children explicitly.
  337.   //
  338.   TFrameWindow::BroadcastResizeToChildren(sizeType, size);
  339. }
  340.  
  341. //
  342. // Handle WM_ENTERIDLE in order to display help hints on the messsage bar if
  343. // there is a hint pending & this frame has a message bar.
  344. //
  345. void
  346. TDecoratedFrame::EvEnterIdle(uint source, HWND hDlg)
  347. {
  348.   if (source == MSGF_MENU && MenuItemId) {
  349.     TMessageBar*  messageBar = TYPESAFE_DOWNCAST(ChildWithId(IDW_STATUSBAR),
  350.                                                  TMessageBar);
  351.     if (messageBar) {
  352.       char  buf[128];
  353.       if ((MenuItemId == BLANK_HELP) ||
  354.           !GetHintText(MenuItemId, buf, sizeof(buf), htStatus))
  355.         *buf = 0;
  356.       messageBar->SetHintText(buf);
  357.     }
  358.     MenuItemId = 0;             // Don't repaint on subsequent EvEnterIdle's
  359.   }
  360.   TFrameWindow::EvEnterIdle(source, hDlg);
  361. }
  362.  
  363. //
  364. // Get or set location codes stashed in the style long for a decoration
  365. //
  366. const uint32 locMask  = 0x0F00;
  367. const int    locShift = 8;
  368.  
  369. inline TDecoratedFrame::TLocation GetLocation(TWindow& w) {
  370.   return TDecoratedFrame::TLocation(uint16((w.Attr.Style & locMask) >> locShift));
  371. }
  372.  
  373. inline void SetLocation(TWindow& w, TDecoratedFrame::TLocation loc) {
  374.   w.Attr.Style = (w.Attr.Style&~locMask) | (uint32(loc) << locShift);
  375. }
  376.  
  377. //
  378. // Find first sibling of a decoration in the same location
  379. //
  380. struct TSiblingSearch {
  381.   TWindow*                   Decoration;
  382.   TDecoratedFrame::TLocation Location;
  383.   TWindow*                   Sibling;
  384.  
  385.   TSiblingSearch(TWindow* decoration, TDecoratedFrame::TLocation location)
  386.   {
  387.     Decoration = decoration;
  388.     Sibling = 0;
  389.     Location = location;
  390.   }
  391. };
  392.  
  393. //
  394. // FirstThat callback function to help EvCommand find decorations that are
  395. // at a given location & that are visible.
  396. //
  397. static bool
  398. findSibling(TWindow* win, void* param)
  399. {
  400.   TSiblingSearch*  search = (TSiblingSearch*)param;
  401.  
  402.   if (win == search->Decoration)
  403.     return true;
  404.  
  405.   else if (GetLocation(*win) == search->Location && win->IsWindowVisible())
  406.     search->Sibling = win;
  407.  
  408.   return false;
  409. }
  410.  
  411. //
  412. //
  413. //
  414. static bool
  415. findFirstSiblingAt(TWindow* win, void* param)
  416. {
  417.   TSiblingSearch*  search = (TSiblingSearch*)param;
  418.   if ((win != search->Decoration) &&
  419.       (GetLocation(*win) == search->Location))
  420.     return true;
  421.   return false;
  422. }
  423.  
  424. //
  425. //
  426. //
  427. TResult
  428. TDecoratedFrame::EvCommand(uint id, HWND hWndCtl, uint notifyCode)
  429. {
  430.   TRACEX(OwlCmd, 1, "TDecoratedFrame:EvCommand - id(" << id << "), ctl(" <<\
  431.                      hex << uint(hWndCtl) << "), code(" << notifyCode  << ")");
  432.  
  433.   // Check if it's a menu-style command (i.e. skip commands from Controls)
  434.   //
  435.   if (hWndCtl == 0) {
  436.  
  437.     // Does the command Id correspond to the Id of one of our children
  438.     //
  439.     TWindow*  decoration = ChildWithId(id);
  440.  
  441.     // If yes, toggle it's visibility
  442.     //
  443.     if (decoration) {
  444.       bool visible = decoration->IsWindowVisible();
  445.  
  446.       // If it's visible, remove it's layout metrics - We'll 'Layout' below
  447.       // and toggle the actual visibility of the child below.
  448.       //
  449.       if (visible) {
  450.         RemoveChildLayoutMetrics(*decoration);
  451.       } else {
  452.  
  453.         // Check if decoration wants to be against the frame's edge
  454.         //
  455.         bool insertAtEdge = decoration->IsFlagSet(wfInsertAtEdge);
  456.  
  457.         // We want to display this child window, first retrieve it's location
  458.         //
  459.         TLocation location = GetLocation(*decoration);
  460.  
  461.         // Find the decoration it should be adjacent to
  462.         //
  463.         TSiblingSearch  search(decoration, location);
  464.         if (insertAtEdge)
  465.           search.Sibling = FirstThat(findFirstSiblingAt, &search);
  466.         else
  467.           FirstThat(findSibling, &search);
  468.  
  469.         // Default to client window if we could not find the decoration's
  470.         // potential neighbor.
  471.         //
  472.         if (!search.Sibling)
  473.           search.Sibling = ClientWnd;
  474.  
  475.         // Insert at its desired location
  476.         //
  477.         switch (location) {
  478.           case Top:
  479.             InsertAtTop(*decoration, search.Sibling);
  480.             break;
  481.  
  482.           case Bottom:
  483.             InsertAtBottom(*decoration, search.Sibling);
  484.             break;
  485.  
  486.           case Left:
  487.             InsertAtLeft(*decoration, search.Sibling);
  488.             break;
  489.  
  490.           case Right:
  491.             InsertAtRight(*decoration, search.Sibling);
  492.             break;
  493.         }
  494.       }
  495.  
  496.       // Force the layout manager to compute new locations and shuffle
  497.       // windows around
  498.       //
  499.       Layout();
  500.  
  501.       // Hide or display the decoration
  502.       //
  503.       decoration->ShowWindow(visible ? SW_HIDE : SW_SHOWNA);
  504.       return 0;
  505.     }
  506.   }
  507.  
  508.   return TFrameWindow::EvCommand(id, hWndCtl, notifyCode);
  509. }
  510.  
  511. //
  512. //
  513. //
  514. void
  515. TDecoratedFrame::EvCommandEnable(TCommandEnabler& commandEnabler)
  516. {
  517.   // Provide default command text to TooltipEnablers
  518.   //
  519.   if (TYPESAFE_DOWNCAST(&commandEnabler, TTooltipEnabler)) {
  520.     char tipText[50];
  521.     if (GetHintText(commandEnabler.GetId(), tipText, sizeof(tipText), htTooltip)) {
  522.       commandEnabler.SetText(tipText);
  523.       return;
  524.     }
  525.   }
  526.  
  527. #if 0
  528.   TWindow*  decoration;
  529.   if (DocAreaTop)
  530.     decoration = DocAreaTop->ChildWithId(commandEnabler.Id);
  531.   else
  532.     decoration = ChildWithId(commandEnabler.Id);
  533. #else
  534.   TWindow*  decoration = ChildWithId(commandEnabler.Id);
  535. #endif
  536.  
  537.   if (!decoration)
  538.     TFrameWindow::EvCommandEnable(commandEnabler);
  539.  
  540.   else {
  541.     commandEnabler.Enable();
  542.     commandEnabler.SetCheck(decoration->IsWindowVisible() ?
  543.                             TCommandEnabler::Checked :
  544.                             TCommandEnabler::Unchecked);
  545.   }
  546. }
  547.  
  548. //
  549. // Insert a decoration window at the top of the client area, possibly above
  550. // another given decoration or the client
  551. //
  552. void
  553. TDecoratedFrame::InsertAtTop(TWindow& decoration, TWindow* insertAbove)
  554. {
  555.   TLayoutMetrics   metrics;
  556.   TWindow*         insertBelow;
  557.  
  558.   // Get the layout metrics for "insertAbove" (the window the decoration is
  559.   // going to be inserted above)
  560.   //
  561.   GetChildLayoutMetrics(*insertAbove, metrics);
  562.  
  563.   insertBelow = metrics.Y.RelWin;
  564.  
  565.   // If "insertAbove" has a border then set its top edge to be the same as
  566.   // the decoration's bottom edge; otherwise place its top edge below the
  567.   // decoration's bottom edge
  568.   //
  569.   metrics.Y.Set(lmTop,
  570.                 insertAbove->Attr.Style & WS_BORDER ? lmSameAs : lmBelow,
  571.                 &decoration, lmBottom);
  572.   SetChildLayoutMetrics(*insertAbove, metrics);
  573.  
  574.   // Now set the layout metrics for the decoration so its top edge is the same
  575.   // as or below the bottom edge of "insertBelow" (they overlap if WS_BORDER)
  576.   //
  577.   bool overlap = (decoration.Attr.Style & WS_BORDER);
  578.  
  579.   metrics.Y.Set(lmTop, overlap ? lmSameAs : lmBelow,
  580.                 insertBelow, insertBelow ? lmBottom : lmTop);
  581.  
  582.   metrics.Height.AsIs(lmHeight);
  583.   metrics.X.Set(lmLeft, overlap ? lmSameAs : lmRightOf, lmParent, lmLeft);
  584.   metrics.Width.Set(lmRight, overlap ? lmSameAs : lmLeftOf, lmParent, lmRight);
  585.  
  586.   SetChildLayoutMetrics(decoration, metrics);
  587. }
  588.  
  589. //
  590. // Insert a decoration window at the bottom of the client area, possibly below
  591. // another given decoration or the client
  592. //
  593. void
  594. TDecoratedFrame::InsertAtBottom(TWindow& decoration, TWindow* insertBelow)
  595. {
  596.   TLayoutMetrics  metrics;
  597.   TWindow*        insertAbove;
  598.  
  599.   // Get the layout metrics for "insertBelow"(the window the decoration is
  600.   // going to be inserted below)
  601.   //
  602.   GetChildLayoutMetrics(*insertBelow, metrics);
  603.  
  604.   if (insertBelow == ClientWnd) {
  605.     insertAbove = metrics.Height.RelWin;
  606.  
  607.     // If the client window has a border then set the client window's bottom
  608.     // to be the same as the top edge of the decoration; otherwise set the
  609.     // client window's bottom edge to be above the decoration's top edge
  610.     //
  611.     metrics.Height.Set(lmBottom,
  612.                        ClientWnd->Attr.Style & WS_BORDER ? lmSameAs : lmAbove,
  613.                        &decoration, lmTop);
  614.   }
  615.   else {
  616.     insertAbove = metrics.Y.RelWin;
  617.  
  618.     // Set the bottom edge of "insertBelow" to be the same as the top edge of
  619.     // the decoration
  620.     //
  621.     metrics.Y.Set(lmBottom, lmSameAs, &decoration, lmTop);
  622.   }
  623.   SetChildLayoutMetrics(*insertBelow, metrics);
  624.  
  625.   // Now set the layout metrics for the decoration so its bottom edge is the
  626.   // same as the top edge of "insertAbove"
  627.   //
  628.   bool overlap = (decoration.Attr.Style & WS_BORDER);
  629.  
  630.   metrics.Y.Set(lmBottom, overlap ? lmSameAs : lmAbove, insertAbove,
  631.                 insertAbove ? lmTop : lmBottom);
  632.  
  633.   metrics.Height.AsIs(lmHeight);
  634.   metrics.X.Set(lmLeft, overlap ? lmSameAs : lmRightOf, lmParent, lmLeft);
  635.   metrics.Width.Set(lmRight, overlap ? lmSameAs : lmLeftOf, lmParent, lmRight);
  636.  
  637.   SetChildLayoutMetrics(decoration, metrics);
  638. }
  639.  
  640. //
  641. // Insert a decoration window at the left of the client area, possibly to the
  642. // left of another given decoration or the client
  643. //
  644. void
  645. TDecoratedFrame::InsertAtLeft(TWindow& decoration, TWindow* insertLeftOf)
  646. {
  647.   TLayoutMetrics  metrics;
  648.   TWindow*        insertRightOf;
  649.  
  650.   // Get the layout metrics for "insertLeftOf"(the window the decoration is
  651.   // going to be inserted to the left of)
  652.   //
  653.   GetChildLayoutMetrics(*insertLeftOf, metrics);
  654.  
  655.   insertRightOf = metrics.X.RelWin;
  656.  
  657.   // If "insertLeftOf" has a border then set its left edge to be the same as
  658.   // the decoration's right edge; otherwise place its left edge one pixel to
  659.   // the right of the decoration's right edge
  660.   //
  661.   metrics.X.Set(lmLeft,
  662.                 insertLeftOf->Attr.Style & WS_BORDER ? lmSameAs : lmRightOf,
  663.                 &decoration, lmRight);
  664.   SetChildLayoutMetrics(*insertLeftOf, metrics);
  665.  
  666.   // Now set the layout metrics for the decoration so it's left edge is the
  667.   // same as the right edge of "insertRightOf"
  668.   //
  669.   bool overlap = (decoration.Attr.Style & WS_BORDER);
  670.  
  671.   metrics.X.Set(lmLeft, overlap ? lmSameAs : lmRightOf, insertRightOf,
  672.                 insertRightOf ? lmRight : lmLeft);
  673.  
  674.   metrics.Width.AsIs(lmWidth);
  675.  
  676.   // If the client window & decoration both have or don't have borders then
  677.   // place the decoration so its "y" and "bottom" are the same as the client
  678.   // windows; otherwise place its "y" above/below the client window's "y" and
  679.   // its "bottom" below/above the client window's "bottom" based on who's has
  680.   // borders & who doesn't
  681.   //
  682.   // This way if there are top or bottom decorations they will be tiled
  683.   // over/under the left/right decorations
  684.   //
  685.   if (ToBool(ClientWnd->Attr.Style & WS_BORDER) == overlap) {
  686.     metrics.Y.SameAs(ClientWnd, lmTop);
  687.     metrics.Height.SameAs(ClientWnd, lmBottom);
  688.   }
  689.   else if (overlap) {
  690.     metrics.Y.Set(lmTop, lmAbove, ClientWnd, lmTop);
  691.     metrics.Height.Set(lmBottom, lmBelow, ClientWnd, lmBottom);
  692.   }
  693.   else {
  694.     metrics.Y.Set(lmTop, lmBelow, ClientWnd, lmTop);
  695.     metrics.Height.Set(lmBottom, lmAbove, ClientWnd, lmBottom);
  696.   }
  697.   SetChildLayoutMetrics(decoration, metrics);
  698. }
  699.  
  700. //
  701. // Insert a decoration window at the right of the client area, possibly to the
  702. // right of another given decoration or the client
  703. //
  704. void
  705. TDecoratedFrame::InsertAtRight(TWindow& decoration, TWindow* insertRightOf)
  706. {
  707.   TLayoutMetrics  metrics;
  708.   TWindow*        insertLeftOf;
  709.  
  710.   // Get the layout metrics for "insertRightOf" (the window the decoration is
  711.   // going to be inserted to the right of)
  712.   //
  713.   GetChildLayoutMetrics(*insertRightOf, metrics);
  714.  
  715.   if (insertRightOf == ClientWnd) {
  716.     insertLeftOf = metrics.Width.RelWin;
  717.  
  718.     // If the client window has a border then set the client window's right
  719.     // edge to be the same as the left edge of the decoration; otherwise set
  720.     // the client window's right edge to be one pixel to the left of the
  721.     // decoration's left edge
  722.     //
  723.     metrics.Width.Set(lmRight,
  724.                       ClientWnd->Attr.Style & WS_BORDER ? lmSameAs : lmLeftOf,
  725.                       &decoration, lmLeft);
  726.   }
  727.   else {
  728.     insertLeftOf = metrics.X.RelWin;
  729.  
  730.     // Set the right edge of "insertRightOf" to be the same as the left edge of
  731.     // the decoration
  732.     //
  733.     metrics.X.Set(lmRight, lmSameAs, &decoration, lmLeft);
  734.   }
  735.   SetChildLayoutMetrics(*insertRightOf, metrics);
  736.  
  737.   // Now set the layout metrics for the decoration so its right edge is the
  738.   // same as the left edge of "insertLeftOf"
  739.   //
  740.   bool overlap = (decoration.Attr.Style & WS_BORDER);
  741.  
  742.   metrics.X.Set(lmRight, overlap ? lmSameAs : lmLeftOf, insertLeftOf,
  743.                 insertLeftOf ? lmLeft : lmRight);
  744.  
  745.   metrics.Width.AsIs(lmWidth);
  746.  
  747.   // If the client window & decoration both have or don't have borders then
  748.   // place the decoration so its "y" and "bottom" are the same as the client
  749.   // windows; otherwise place its "y" above/below the client window's "y" and
  750.   // its "bottom" below/above the client window's "bottom" based on who's has
  751.   // borders & who doesn't
  752.   //
  753.   // This way if there are top or bottom decorations they will be tiled
  754.   // over/under the left/right decorations
  755.   //
  756.   if (ToBool(ClientWnd->Attr.Style & WS_BORDER) == overlap) {
  757.     metrics.Y.SameAs(ClientWnd, lmTop);
  758.     metrics.Height.SameAs(ClientWnd, lmBottom);
  759.   }
  760.   else if (overlap) {
  761.     metrics.Y.Set(lmTop, lmAbove, ClientWnd, lmTop);
  762.     metrics.Height.Set(lmBottom, lmBelow, ClientWnd, lmBottom);
  763.   }
  764.   else {
  765.     metrics.Y.Set(lmTop, lmBelow, ClientWnd, lmTop);
  766.     metrics.Height.Set(lmBottom, lmAbove, ClientWnd, lmBottom);
  767.   }
  768.   SetChildLayoutMetrics(decoration, metrics);
  769. }
  770.  
  771. //
  772. // Insert a decoration window into position at one of the four edges.
  773. //
  774. void
  775. TDecoratedFrame::Insert(TWindow& decoration, TLocation location)
  776. {
  777.   // Store away location for remove/re-insetion
  778.   //
  779.   SetLocation(decoration, location);
  780.  
  781.   // Make sure the decoration has clipsiblings style, since our rearranging
  782.   // causes corners to overlap sometimes.
  783.   //
  784.   ModifyStyle(0, WS_CLIPSIBLINGS);
  785.  
  786.   // Parent to decframe and remove layoutmetrics in case it's a re-insert
  787.   //
  788.   decoration.SetParent(this);
  789.   RemoveChildLayoutMetrics(decoration);
  790.  
  791.   // If the window should be visible, proceed with insertion.
  792.   // NOTE: Should we check the 'wfInsertAtEdge' flag here? It mostly
  793.   //       important when hiding/showing decorations [i.e. In EvCommand
  794.   //       handler]. However, it would be nice to check for it and use
  795.   //       something other than ClientWnd if necessary.
  796.   //
  797.   if (decoration.Attr.Style & WS_VISIBLE) {
  798.     switch (location) {
  799.       case Top:
  800.         InsertAtTop(decoration, ClientWnd);
  801.         break;
  802.       case Bottom:
  803.         InsertAtBottom(decoration, ClientWnd);
  804.         break;
  805.       case Left:
  806.         InsertAtLeft(decoration, ClientWnd);
  807.         break;
  808.       case Right:
  809.         InsertAtRight(decoration, ClientWnd);
  810.         break;
  811.     }
  812.   }
  813. }
  814.  
  815. #endif
  816. #if !defined(SECTION) || SECTION == 2
  817.  
  818. IMPLEMENT_STREAMABLE3(TDecoratedFrame, TFrameWindow, TLayoutWindow, TWindow);
  819.  
  820. #if !defined(BI_NO_OBJ_STREAMING)
  821.  
  822. //
  823. //
  824. //
  825. void*
  826. TDecoratedFrame::Streamer::Read(ipstream& is, uint32 /*version*/) const
  827. {
  828.   ReadVirtualBase((TFrameWindow*)GetObject(), is);
  829.   ReadBaseObject((TLayoutWindow*)GetObject(), is);
  830.   return GetObject();
  831. }
  832.  
  833. //
  834. //
  835. //
  836. void
  837. TDecoratedFrame::Streamer::Write(opstream& os) const
  838. {
  839.   WriteVirtualBase((TFrameWindow*)GetObject(), os);
  840.   WriteBaseObject((TLayoutWindow*)GetObject(), os);
  841. }
  842.  
  843. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  844.  
  845. #endif
  846.